package roadsuggester.main;

import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.List;

import roadsuggester.db.UserLocationsDatabase;
import roadsuggester.db.UserLocationsDatabase.UserLocation;
import roadsuggester.navigation.NavigationInterface;
import roadsuggester.navigation.Road;
import roadsuggester.navigation.RoadProvider;
import roadsuggester.testing.MockLocationProvider;
import roadsuggester.tracks.GoogleTrackOverlay;
import roadsuggester.tracks.NavigationTrackOverlay;
import roadsuggester.tracks.RecordedTrack;

import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapController;
import com.google.android.maps.MapView;
import com.google.android.maps.Overlay;
import com.google.android.maps.OverlayItem;

import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;


//The map that appears when the user clicks.
public class TrackerMap extends com.google.android.maps.MapActivity
{
	public static int CurrentTrack=0; //for mock-gps testing
	public static int TRACKS_COUNT=3;

	private MapView mapView;
	private MapController mapController;
	private TrackerMapOverlay overlay;
	private DestinationProximityCalculator destinationProximityCalculator;
	private boolean destinationReached;
	private RecordedTrack recordedTrack;

	private Location currentLocation=null;
	private UserLocation destination;
	private Location startLocation=null;

	private boolean mapActivityFinalized=false;

	private boolean googleNavigationOverlayActivated=false;
	private boolean databaseTrackOverlayActivated=false;
	private GoogleTrackOverlay googleTrackOverlay;

	@Override
	public void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);

		setContentView(R.layout.locatormap);
		mapView=(MapView) findViewById(R.id.mapview);
		mapController=mapView.getController();


		UserLocationsDatabase db=UserLocationsDatabase.getInstance(this);
		destination=db.getLocationByID(getIntent().getLongExtra("destinationID", -1));
		db.close();

		mapController.setZoom(17);
		mapView.setBuiltInZoomControls(true);
		mapView.displayZoomControls(true);
		mapView.showContextMenu();


		recordedTrack=new RecordedTrack();
		overlay=new TrackerMapOverlay(getApplicationContext(), destination, recordedTrack);
		List<Overlay> listOfOverlays=mapView.getOverlays();
		listOfOverlays.clear();
		listOfOverlays.add(overlay);

		mapView.invalidate();


		this.destinationProximityCalculator=new DestinationProximityCalculator(this, destination);
		this.destinationReached=false;

		currentLocation=null;
		mapActivityFinalized=false;
		googleNavigationOverlayActivated=false;
		databaseTrackOverlayActivated=false;
		googleTrackOverlay=null;


		registerLocationProvider();
		registerHeadingProvider();

	}


	private Location getLastKnownLocation()
	{
		LocationManager lm=(LocationManager) getSystemService(Context.LOCATION_SERVICE);
		List<String> providers=lm.getProviders(true);

		Location l=null;

		for(int i=providers.size()-1; i>=0; i--)
		{
			l=lm.getLastKnownLocation(providers.get(i));
			if(l!=null)
				break;
		}
		return l;
	}


	private void registerLocationProvider()
	{
		LocationManager locationManager=(LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
		LocationListener locationListener=new LocationListener()
		{
			public void onLocationChanged(Location location)
			{
				//Address currentAddress=Utils.getFromLocation(TrackerMap.this, location.getLatitude(), location.getLongitude());
				//Utils.showToastText(TrackerMap.this, currentAddress.getAddressLine(0));
				if(mapActivityFinalized)
				{
					return;
				}

				if(destinationReached==false)
				{
					mapController.setCenter(Utils.locationToGeoPoint(location));
					overlay.setLocation(location);
				}
				if(destinationProximityCalculator.hasReachedDestination(location))
				{
					overlay.setDestinationReached(true);
					TrackerMap.this.setDestinationReached(true);
				}

				if(currentLocation==null)
				{
					startLocation=location;
					setNavigationTrack();
				}
				currentLocation=location;
			}

			public void onStatusChanged(String provider, int status, Bundle extras)
			{
			}

			public void onProviderEnabled(String provider)
			{
			}

			public void onProviderDisabled(String provider)
			{
			}
		};


		if(destination.label.equals("Home"))
		{
			//The hard-coded mock location provider for the home destination.
			String mockLocationProvider="CUSTOM_MOCK_LOCATION_PROVIDER"+Math.random(); //This is a hack.
			locationManager.addTestProvider(mockLocationProvider, false, false, false, false, true, true, true, 0, 5);
			locationManager.setTestProviderEnabled(mockLocationProvider, true);
			locationManager.requestLocationUpdates(mockLocationProvider, 0, 0, locationListener);

			try
			{
				InputStream dataInputStream=getAssets().open("home_threeblocks_"+CurrentTrack+".gps");
				CurrentTrack=(CurrentTrack+1)%TRACKS_COUNT;
				new MockLocationProvider(this, locationManager, mockLocationProvider, dataInputStream).start();
			}
			catch(IOException e)
			{
				// TODO Auto-generated catch block
				e.printStackTrace();
			}


		}
		else
		{

			locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListener);
			locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locationListener);
		}
	}


	private void registerHeadingProvider()
	{
		final SensorEventListener mListener=new SensorEventListener()
		{
			public void onSensorChanged(SensorEvent event)
			{
				overlay.setHeading(event.values[0]);
			}

			@Override
			public void onAccuracyChanged(Sensor arg0, int arg1)
			{

			}
		};
		SensorManager mSensorManager=(SensorManager) getSystemService(Context.SENSOR_SERVICE);
		Sensor mSensor=mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION);
		mSensorManager.registerListener(mListener, mSensor, SensorManager.SENSOR_DELAY_GAME);

	}

	protected void setDestinationReached(boolean destinationReached)
	{
		if(this.destinationReached)
		{
			return;
		}
		this.destinationReached=destinationReached;

		new Thread()
		{
			public void run()
			{
				NavigationInterface.addTrack(recordedTrack);
			}
		}.start();

		AlertDialog.Builder builder=new AlertDialog.Builder(this);
		builder.setMessage("You have reached your destination. Do you want to exit?").setCancelable(false)
				.setPositiveButton("Yes", new DialogInterface.OnClickListener()
				{
					public void onClick(DialogInterface dialog, int id)
					{
						TrackerMap.this.finish();

					}
				}).setNegativeButton("No", new DialogInterface.OnClickListener()
				{
					public void onClick(DialogInterface dialog, int id)
					{
						dialog.cancel();
					}
				});
		AlertDialog alert=builder.create();
		alert.show();

	}

	private void setNavigationTrack()
	{
		final Location from=startLocation;
		final Location to=destination.toLocation();
		RecordedTrack track=NavigationInterface.getTrack(from, to);
		if(track!=null)
		{
			NavigationTrackOverlay trackOverlay=new NavigationTrackOverlay(track);
			List<Overlay> listOfOverlays=mapView.getOverlays();
			listOfOverlays.add(trackOverlay);
			databaseTrackOverlayActivated=true;
			return;
		}

		AlertDialog.Builder builder=new AlertDialog.Builder(this);
		builder.setMessage("No tracks were found in the database for this route. Do you want to get navigation from google?").setCancelable(false)
				.setPositiveButton("Yes", new DialogInterface.OnClickListener()
				{
					public void onClick(DialogInterface dialog, int id)
					{
						addGoogleNavigationOverlay();
					}
				}).setNegativeButton("No", new DialogInterface.OnClickListener()
				{
					public void onClick(DialogInterface dialog, int id)
					{
						dialog.cancel();
					}
				});
		AlertDialog alert=builder.create();
		alert.show();

	}

	private void addGoogleNavigationOverlay(final Location from, final Location to)
	{
		if(googleTrackOverlay!=null)
		{
			List<Overlay> listOfOverlays=mapView.getOverlays();
			listOfOverlays.remove(googleTrackOverlay);

		}
		new Thread()
		{
			public void run()
			{
				googleNavigationOverlayActivated=true;


				String url=RoadProvider.getUrl(from.getLatitude(), from.getLongitude(), to.getLatitude(), to.getLongitude());
				InputStream is=getConnection(url);
				Road mRoad=RoadProvider.getRoute(is);

				googleTrackOverlay=new GoogleTrackOverlay(mRoad, mapView, Color.GREEN);
				List<Overlay> listOfOverlays=mapView.getOverlays();
				listOfOverlays.add(googleTrackOverlay);
			}
		}.start();
	}

	private void addGoogleNavigationOverlay()
	{
		final Location from=startLocation;
		final Location to=destination.toLocation();
		addGoogleNavigationOverlay(from, to);
	}


	private InputStream getConnection(String url)
	{
		InputStream is=null;
		try
		{
			URLConnection conn=new URL(url).openConnection();
			is=conn.getInputStream();
		}
		catch(MalformedURLException e)
		{
			e.printStackTrace();
		}
		catch(IOException e)
		{
			e.printStackTrace();
		}
		return is;
	}

	@Override
	public void finish()
	{
		mapActivityFinalized=true;
		super.finish();

	}

	protected boolean isRouteDisplayed()
	{
		return false;
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu)
	{
		MenuInflater inflater=getMenuInflater();
		inflater.inflate(R.menu.trackermap_menu, menu);
		return true;
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item)
	{
		// Handle item selection
		switch (item.getItemId())
		{
		case R.id.showGoogleNavigation:
			addGoogleNavigationOverlay(currentLocation, destination.toLocation());
			return true;
		default:
			return super.onOptionsItemSelected(item);
		}
	}

}
